﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;


namespace Lon.Server
{



    public class DataPackage
    {
        private const string DATABUF_KEY = "___DataBuf___";

        public DataPackage()
        {
            this.DataNode = new Node();
            this.Flags = 0;
            this.SendTime = DateTime.MinValue;
            this.PackageId = Util.GetTickCount();
            this.DataFrom = DataFromType.FROM_STATION;
            this.IsCommand = true;
        }

        public DataPackage(ushort majorDataType, ushort minorDataType)
            : this()
        {
            this.MajorDataType = majorDataType;
            this.MinorDataType = minorDataType;
        }

        public DataPackage(ushort majorDataType, ushort minorDataType, bool isHHSelfPackage)
            : this()
        {
            this.MajorDataType = majorDataType;
            this.MinorDataType = minorDataType;
            this.IsHHSelfPackage = isHHSelfPackage;
        }

       

        public byte[] Pack()
        {
            int bufLen = 0;
            byte[] dataNodeBuf = null;
            if (this.IsHHSelfPackage)
            {
                int routeLen = 0;
                if (this.IsRecordRoute)
                {
                    routeLen = 2 + (this.RouteIDList.Count * 4);
                }
                if (this.DataBuf != null)
                {
                    this.DataNode["___DataBuf___"] = this.DataBuf;
                }
                dataNodeBuf = this.DataNode.Pack();
                bufLen = (((10 + (this.IsCommand ? 0 : 1)) + 0x1a) + routeLen) + dataNodeBuf.Length;
            }
            else
            {
                bufLen = (10 + (this.IsCommand ? 0 : 1)) + ((this.DataBuf == null) ? 0 : this.DataBuf.Length);
            }
            byte[] buf = new byte[bufLen];
            BinaryWriter bw = new BinaryWriter(new MemoryStream(buf), Encoding.Unicode);
            bw.Write(this.DestID);
            bw.BaseStream.Seek(-1, SeekOrigin.Current);
            bw.Write(this.SrcID);
            bw.BaseStream.Seek(-1, SeekOrigin.Current);
            bw.Write(this.IsCommand ? ((byte)1) : ((byte)0));
            if (!this.IsCommand)
            {
                bw.Write(this.IsCompress ? ((byte)1) : ((byte)0));
            }
            if (this.DataFrom == DataFromType.FROM_SERVER)
            {
                bw.Write((byte)0xe1);
            }
            else if (this.DataFrom == DataFromType.FROM_STATION)
            {
                bw.Write((byte)0xe0);
            }
            else
            {
                bw.Write((byte)0);
            }
            if (this.IsHHSelfPackage)
            {
                bw.Write((byte)0x40);
                bw.Write((byte)2);
                bw.Write(this.MajorDataType);
                bw.Write(this.MinorDataType);
                bw.Write(this.PackageId);
                bw.Write(this.TransCount);
                bw.Write(this.SendTime.ToBinary());
                bw.Write(this.Flags);
                if (this.IsRecordRoute)
                {
                    if (this.RouteIDList == null)
                    {
                        bw.Write((short)0);
                    }
                    else
                    {
                        bw.Write((short)this.RouteIDList.Count);
                        foreach (int routeId in this.RouteIDList)
                        {
                            bw.Write(routeId);
                        }
                    }
                }
                if (dataNodeBuf != null)
                {
                    bw.Write(dataNodeBuf.Length);
                    bw.Write(dataNodeBuf);
                    return buf;
                }
                bw.Write(0);
                return buf;
            }
            bw.Write((byte)this.MajorDataType);
            if (this.MajorDataType != 0x23)
            {
                bw.Write((byte)this.MinorDataType);
            }
            if (this.DataBuf != null)
            {
                bw.Write(this.DataBuf);
            }
            return buf;
        }

        public string ToStringDesc(int maxValueLen)
        {
            if (maxValueLen < 20)
            {
                maxValueLen = 20;
            }
            if ((this.MajorDataType == 0x7002) && (this.MinorDataType == 2))
            {
            }
            StringBuilder sb = new StringBuilder();
            try
            {
                string context = ((HistoryDataType)this.MajorDataType).ToString();
                sb.Append("数据类型：").Append(" 0x").Append(this.MajorDataType.ToString("X").PadLeft(4, '0')).Append(" 子类型：").Append("0x").Append(this.MinorDataType.ToString("X").PadLeft(4, '0')).Append("  HistoryDataType.").Append(context).AppendLine();
                sb.Append("数据来源：").Append(this.DataFrom).AppendLine();
                if (!this.IsHHSelfPackage)
                {
                    sb.Append("按互联互通协议执行").AppendLine();
                    if ((this.DataBuf != null) && (this.DataBuf.Length > 0))
                    {
                        sb.Append("数据包内容：").Append(Util.BinaryToString(this.DataBuf, maxValueLen));
                    }
                    return sb.ToString();
                }
                sb.Append("源电报码：").Append(this.SrcDBM).Append(" 目的电报码：").Append(this.DestDBM).AppendLine();
                sb.Append("协议格式：").Append("辉煌自定义").AppendLine();
                sb.AppendLine("参数表：");
                Dictionary<string, Variable> dict = this.DataNode.GetValDict();
                List<string> lst = new List<string> { "__DataFrom", "__TimeoutMillisecond", "__ProgressWaitInfo" };
                if ((this.DataBuf != null) && (this.DataBuf.Length > 0))
                {
                    sb.Append("___DataBuf___\t    ").Append("- ").Append(VarType.Binary.ToString()).Append("\t- ").Append(Util.BinaryToString(this.DataBuf, maxValueLen));
                }
                foreach (string key in dict.Keys)
                {
                    if (!lst.Contains(key))
                    {
                        Variable var = dict[key];
                        string keyDesc = key;
                        int nnn = 20 - (this.GetStringLen(keyDesc) - keyDesc.Length);
                        keyDesc = keyDesc.PadRight(nnn, ' ');
                        string varTypeDesc = var.VarType.ToString();
                        nnn = 10 - (this.GetStringLen(varTypeDesc) - varTypeDesc.Length);
                        varTypeDesc = varTypeDesc.PadRight(nnn, ' ');
                        string varValueDesc = var.Value.ToString();
                        if (var.Value is byte[])
                        {
                            varValueDesc = Util.BufferFormatSimple((byte[])var.Value);
                        }
                        if (varValueDesc.Length > maxValueLen)
                        {
                            varValueDesc = varValueDesc.Substring(0, maxValueLen) + "...";
                        }
                        if (!"__SQLWhereString".Equals(key) || !string.IsNullOrEmpty(varValueDesc))
                        {
                            sb.Append(keyDesc).Append("- ").Append(varTypeDesc).Append("- ").Append(varValueDesc).AppendLine();
                        }
                    }
                }
            }
            catch
            {
            }
            return sb.ToString();
        }

        public bool UnPack(byte[] buf)
        {
            BinaryReader br = new BinaryReader(new MemoryStream(buf), Encoding.Unicode);
            this.DestID = br.ReadInt32() & 0xffffff;
            br.BaseStream.Seek(-1, SeekOrigin.Current);
            this.SrcID = br.ReadInt32() & 0xffffff;
            br.BaseStream.Seek(-1, SeekOrigin.Current);
            this.IsCommand = br.ReadByte() == 1;
            if (!this.IsCommand)
            {
                this.IsCompress = br.ReadByte() == 1;
            }
            byte v = br.ReadByte();
            if (v == 0xe1)
            {
                this.DataFrom = DataFromType.FROM_SERVER;
            }
            else if (v == 0xe0)
            {
                this.DataFrom = DataFromType.FROM_STATION;
            }
            else
            {
                this.DataFrom = DataFromType.SERVER_AUTO_DECISION;
            }
            this.MajorDataType = br.ReadByte();
            if (this.MajorDataType != 0x23)
            {
                this.MinorDataType = br.ReadByte();
            }
            if ((this.MajorDataType == 0x40) && (this.MinorDataType == 2))
            {
                this.IsHHSelfPackage = true;
                this.MajorDataType = br.ReadUInt16();
                this.MinorDataType = br.ReadUInt16();
                this.PackageId = br.ReadUInt32();
                this.TransCount = br.ReadUInt16();
                this.TransCount = (ushort)(this.TransCount + 1);
                this.SendTime = DateTime.FromBinary(br.ReadInt64());
                this.Flags = br.ReadInt32();
                if (this.IsRecordRoute)
                {
                    int routeCount = br.ReadInt16();
                    if (this.RouteIDList == null)
                    {
                        this.RouteIDList = new List<int>();
                    }
                    for (int i = 0; i < routeCount; i++)
                    {
                        this.RouteIDList.Add(br.ReadInt32());
                    }
                }
                int dataLen = br.ReadInt32();
                if (dataLen > 0)
                {
                    byte[] data = br.ReadBytes(dataLen);
                    if (data != null)
                    {
                        if (this.IsDataBufByteStreamFormat)
                        {
                            this.DataBuf = data;
                        }
                        else
                        {
                            Node.UnPack(this.DataNode, data);
                        }
                    }
                    if (this.DataNode.ContainsKey("___DataBuf___"))
                    {
                        this.DataBuf = (byte[])this.DataNode["___DataBuf___"];
                        this.DataNode.RemoveValue("___DataBuf___");
                    }
                }
            }
            else
            {
                this.DataBuf = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position));
            }
            return true;
        }

        public byte[] DataBuf { get; set; }

       




        public int DestID { get; set; }

        public int Flags { get; set; }

        public int FromLinkID { get; set; }

        public bool IsCommand { get; set; }

        public bool IsCompress
        {
            get
            {
                return Util.GetIntBitValue(this.Flags, 1);
            }
            private set
            {
                this.Flags = Util.SetIntBitValue(this.Flags, 1, value);
            }
        }

        public bool IsDataBufByteStreamFormat
        {
            get
            {
                return Util.GetIntBitValue(this.Flags, 3);
            }
            set
            {
                this.Flags = Util.SetIntBitValue(this.Flags, 3, value);
            }
        }

        public bool IsHHSelfPackage { get; set; }

        public bool IsNeedReceipt
        {
            get
            {
                return Util.GetIntBitValue(this.Flags, 0);
            }
            set
            {
                this.Flags = Util.SetIntBitValue(this.Flags, 0, value);
            }
        }

        public bool IsRecordRoute
        {
            get
            {
                return Util.GetIntBitValue(this.Flags, 2);
            }
            set
            {
                this.Flags = Util.SetIntBitValue(this.Flags, 2, value);
            }
        }

        public ushort MajorDataType { get; set; }

        public ushort MinorDataType { get; set; }

        public uint PackageId { get; set; }

        public DateTime RecvTime { get; set; }

        public List<int> RouteIDList { get; set; }

        public DateTime SendTime { get; set; }

        public string SrcDBM
        {
            get
            {
                return Util.Int2DBM(this.SrcID);
            }
            set
            {
                this.SrcID = Util.DBM2Int(value);
            }
        }

        public int SrcID { get; set; }

        public ushort TransCount { get; set; }
    }
}

